﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class NodeBaseEditor : EditorWindow {
    /// <summary>
    /// 应该被绘制的节点
    /// </summary>
    private List<Node> nodes;
    private List<Connect> connects;

    private GUIStyle nodeStyle;
    private GUIStyle inPointStyle;
    private GUIStyle outPointStyle;
    private GUIStyle selectNodeStyle;

    private ConnectPoint selectInPoint;
    private ConnectPoint selectOutPoint;

    private Vector2 offset;
    private Vector2 Drag;
    [MenuItem("Window/NodeBaseEditor")]
    public static void OpenWindow()
    {
        NodeBaseEditor window = GetWindow<NodeBaseEditor>();
        window.titleContent = new GUIContent("Node Base Editor");
    }
    private void OnGUI()
    {
        DrawGrid(20, 0.2f, Color.gray);
        DrawGrid(100, 0.4f, Color.gray);

        DrawNodes();
        DrawConnects();

        DrawConnectionLine(Event.current);

        ProcessEvent(Event.current);
        ProcessNodeEvent(Event.current);

        if (GUI.changed)
        {
            Repaint();
        }
    }
    private void OnEnable()
    {
        nodeStyle = new GUIStyle();
        //nodeStyle.normal.background = EditorGUIUtility.Load("Assets/NodeEditor/Image/node1.png") as Texture2D;
        nodeStyle.normal.background = EditorGUIUtility.Load("node1.png") as Texture2D;
        nodeStyle.border = new RectOffset(12,12,12,12);

        inPointStyle = new GUIStyle();
        inPointStyle.normal.background = EditorGUIUtility.Load("btn left.png") as Texture2D;
        inPointStyle.active.background = EditorGUIUtility.Load("btn left on.png") as Texture2D;
        inPointStyle.border = new RectOffset(4,4,12,12);

        outPointStyle = new GUIStyle();
        outPointStyle.normal.background = EditorGUIUtility.Load("btn right.png") as Texture2D;
        outPointStyle.active.background = EditorGUIUtility.Load("btn right on.png") as Texture2D;
        outPointStyle.border = new RectOffset(4, 4, 12, 12);

        selectNodeStyle = new GUIStyle();
        selectNodeStyle.normal.background = EditorGUIUtility.Load("node1 on.png") as Texture2D;
        selectNodeStyle.border = new RectOffset(12,12,12,12);
    }
    /// <summary>
    /// 绘制所有链接
    /// </summary>
    private void DrawConnects()
    {
        if (connects!=null)
        {
            for(int i=0;i<connects.Count;i++)
            {
                connects[i].Draw();
            }
        }
    }
    /// <summary>
    /// 绘制所有节点
    /// </summary>
    private void DrawNodes()
    {
        //只有在初始化完成之后才可以进行绘制
        if (nodes!=null)
        {
            for (int i = 0; i < nodes.Count; i++)
            {
                nodes[i].Draw();
            }
        }
    }   
    /// <summary>
    /// 界面响应事件
    /// </summary>
    /// <param name="s"></param>
    private void ProcessEvent(Event e)
    {
        Drag = Vector2.zero;

        switch (e.type)
        {
            case EventType.MouseDown:
                if (e.button==1)
                {
                    ProcessContextMenu(e.mousePosition);
                }
                break;
            case EventType.MouseDrag:
                if (e.button==0)
                {
                    OnDrag(e.delta);
                }
                break;
            default:
                break;
        }
    }
    /// <summary>
    /// 鼠标右键菜单
    /// </summary>
    /// <param name="mousePosition"></param>
    private void ProcessContextMenu(Vector2 mousePosition)
    {
        GenericMenu genericMenu = new GenericMenu();
        genericMenu.AddItem(new GUIContent("Add Node"),false,()=>OnClickAddNode(mousePosition));
        genericMenu.ShowAsContext();
    }
    /// <summary>
    /// 调用node响应
    /// </summary>
    /// <param name="e"></param>
    private void ProcessNodeEvent(Event e)
    {
        if (nodes!=null)
        {
            for (int i=nodes.Count-1;i>=0;i--)
            {
                bool guiChanged = nodes[i].ProcessEvents(e);

                if (guiChanged)
                {
                    GUI.changed = true;
                }
            }
        }
    }
    /// <summary>
    /// 监听按下创建节点之后的操作（创建一个节点）
    /// </summary>
    /// <param name="mousePosition"></param>
    private void OnClickAddNode(Vector2 mousePosition)
    {
        if (nodes==null)
        {
            nodes = new List<Node>();
        }
        nodes.Add(new Node(mousePosition,200,50,nodeStyle,selectNodeStyle,inPointStyle,outPointStyle,
            OnClickInPoint,OnClickOutPoint, OnClickRemoveNode));
    }
    /// <summary>
    /// 输入端口响应
    /// </summary>
    /// <param name="inPoint"></param>
    private void OnClickInPoint(ConnectPoint inPoint)
    {
        selectInPoint = inPoint;

        if (selectOutPoint!=null)
        {
            if (selectInPoint.node != selectOutPoint.node)
            {
                CreatConnection();
                ClearConnectionSelection();
            }
            else
            {
                ClearConnectionSelection();
            }
        }
    }
    /// <summary>
    /// 输出端口响应
    /// </summary>
    /// <param name="outPoint"></param>
    private void OnClickOutPoint(ConnectPoint outPoint)
    {
        selectOutPoint = outPoint;
        if (selectInPoint!=null)
        {
            if (selectOutPoint.node != selectInPoint.node)
            {
                CreatConnection();
                ClearConnectionSelection();
            }
            else
            {
                ClearConnectionSelection();
            }
        }
    }
    /// <summary>
    /// 移除连线
    /// </summary>
    /// <param name="connect"></param>
    private void OnClickRemoveConnection(Connect connect)
    {
        connects.Remove(connect);
    }
    /// <summary>
    /// 创建连线
    /// </summary>
    private void CreatConnection()
    {
        if (connects==null)
        {
            connects = new List<Connect>();
        }
        connects.Add(new Connect(selectInPoint,selectOutPoint,OnClickRemoveConnection));
    }
    /// <summary>
    /// 清空选择
    /// </summary>
    private void ClearConnectionSelection()
    {
        selectInPoint = null;
        selectOutPoint = null;
    }
    /// <summary>
    /// 移除节点(先移除所有关联连线，再移除节点)
    /// </summary>
    /// <param name="node"></param>
    private void OnClickRemoveNode(Node node)
    {
        if (connects!=null)
        {
            List<Connect> connectsToRemove = new List<Connect>();

            for (int i=0;i<connects.Count;i++)
            {
                if (connects[i].inPoint==node.inPoint||connects[i].outPoint==node.outPoint)
                {
                    connectsToRemove.Add(connects[i]);
                }
            }

            for (int i=0;i<connectsToRemove.Count;i++)
            {
                connects.Remove(connectsToRemove[i]);
            }
        }
        nodes.Remove(node);
    }
    /// <summary>
    /// 移动画布
    /// </summary>
    /// <param name="Drag"></param>
    private void OnDrag(Vector2 Drag)
    {
        this.Drag = Drag;

        if (nodes!=null)
        {
            for (int i=0;i<nodes.Count;i++)
            {
                nodes[i].Drag(Drag);
            }
        }

        GUI.changed = true;
    }
    /// <summary>
    /// 绘制贝塞尔曲线在鼠标处
    /// </summary>
    /// <param name="e"></param>
    private void DrawConnectionLine(Event e)
    {
        if (selectInPoint!=null&&selectOutPoint==null)
        {
            Handles.DrawBezier(
                selectInPoint.rect.center,
                e.mousePosition,
                selectInPoint.rect.center+Vector2.left*50f,
                e.mousePosition-Vector2.left*50f,
                Color.white,
                null,
                2f
                );
            GUI.changed = true;
        }

        if (selectOutPoint != null && selectInPoint == null)
        {
            Handles.DrawBezier(
                selectOutPoint.rect.center,
                e.mousePosition,
                selectOutPoint.rect.center - Vector2.left * 50f,
                e.mousePosition + Vector2.left * 50f,
                Color.white,
                null,
                2f
                );
            GUI.changed = true;
        }
    }

    private void DrawGrid(float gridSpacing, float gridOpacity, Color gridColor)
    {
        int widthDivs = Mathf.CeilToInt(position.width / gridSpacing);
        int heightDivs = Mathf.CeilToInt(position.height / gridSpacing);
        Handles.BeginGUI(); Handles.color = new Color(gridColor.r, gridColor.g, gridColor.b, gridOpacity);
        offset += Drag * 0.5f; Vector3 newOffset = new Vector3(offset.x % gridSpacing, offset.y % gridSpacing, 0);
        for (int i = 0; i < widthDivs; i++) {
            Handles.DrawLine(new Vector3(gridSpacing * i, -gridSpacing, 0) + newOffset, new Vector3(gridSpacing * i, position.height, 0f) + newOffset);
        }
        for (int j = 0; j < heightDivs; j++) {
            Handles.DrawLine(new Vector3(-gridSpacing, gridSpacing * j, 0) + newOffset, new Vector3(position.width, gridSpacing * j, 0f) + newOffset);
        }
        Handles.color = Color.white; Handles.EndGUI();
    }
}
